package drawer

import (
	"MetroBuilderGameJam/gameEngine/geom"
	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/vector"
	"image/color"
	"math"
)

type FigureAnchor int

const (
	AnchorTopLeft FigureAnchor = iota
	AnchorTop
	AnchorTopRight
	AnchorLeft
	AnchorCenter
	AnchorRight
	AnchorBottomLeft
	AnchorBottom
	AnchorBottomRight
)

func (d *Drawer) Point(dst *ebiten.Image, pos geom.Point, w float64, clr color.Color) {
	vector.DrawFilledCircle(dst, float32(pos.X+d.Offset.X), float32(pos.Y+d.Offset.Y), float32(w), clr, false)
}

func (d *Drawer) Circle(dst *ebiten.Image, pos geom.Point, radius, w float64, clr color.Color) {
	offset := d.applyAnchor(d.Offset.AsVec2().Add(pos.AsVec2()), geom.Size{radius, radius})
	vector.StrokeCircle(dst, float32(offset.X), float32(offset.Y), float32(radius), float32(w), clr, false)
	d.drawPivot(dst, pos, clr)
}

func (d *Drawer) Square(dst *ebiten.Image, pos geom.Point, size, w float64, rotation geom.Radian, clr color.Color) {
	d.Rectangle(dst, pos, geom.Size{Width: size, Height: size}, w, rotation, clr)
}

func (d *Drawer) Rectangle(dst *ebiten.Image, pos geom.Point, size geom.Size, w float64, rotation geom.Radian, clr color.Color) {
	path := vector.Path{}

	p1, p2, p3, p4 := d.GetRectanglePoints(pos, size, rotation)
	path.MoveTo(p1.X, p1.Y)
	path.LineTo(p2.X, p2.Y)
	path.LineTo(p3.X, p3.Y)
	path.LineTo(p4.X, p4.Y)
	path.LineTo(p1.X, p1.Y)

	vs, is, op := d.preparePathToDraw(path, w, clr)
	d.drawPath(dst, vs, is, op)

	d.drawPivot(dst, pos, clr)
}

func (d *Drawer) SimpleRectangle(dst *ebiten.Image, pos geom.Point, size geom.Size, w float64, clr color.Color) {
	path := vector.Path{}
	offset := d.applyAnchor(d.Offset.AsVec2().Add(pos.AsVec2()), size)

	path.MoveTo(float32(offset.X), float32(offset.Y))
	path.LineTo(float32(offset.X+size.Width), float32(offset.Y))
	path.LineTo(float32(offset.X+size.Width), float32(offset.Y+size.Height))
	path.LineTo(float32(offset.X), float32(offset.Y+size.Height))
	path.LineTo(float32(offset.X), float32(offset.Y))

	vs, is, op := d.preparePathToDraw(path, w, clr)
	d.drawPath(dst, vs, is, op)

	d.drawPivot(dst, pos, clr)
}

func (d *Drawer) SimpleTriangle(dst *ebiten.Image, pos geom.Point, size, w float64, rotation geom.Radian, clr color.Color) {
	path := d.GetPathForSimpleTriangle(pos, size, rotation)

	vs, is, op := d.preparePathToDraw(path, w, clr)
	d.drawPath(dst, vs, is, op)

	d.drawPivot(dst, pos, clr)
}

func (d *Drawer) GetPathForSimpleTriangle(pos geom.Point, size float64, rotation geom.Radian) vector.Path {
	size *= 1.4
	path := vector.Path{}
	offset := d.applyAnchor(d.Offset.AsVec2().Add(pos.AsVec2()), geom.Size{Width: size, Height: size})

	for i := 0; i <= 3; i++ {
		theta := 2*math.Pi*float64(i)/3 - math.Pi/2 + float64(rotation)
		x := offset.X + size*math.Cos(theta)
		y := offset.Y + size*math.Sin(theta)
		if i == 0 {
			path.MoveTo(float32(x), float32(y))
		} else {
			path.LineTo(float32(x), float32(y))
		}
	}

	return path
}

func (d *Drawer) Triangle(dst *ebiten.Image, pivot, a, b, c geom.Point, w float64, clr color.Color) {
	path := vector.Path{}

	offset := d.applyAnchor(d.Offset.AsVec2().Add(pivot.AsVec2()), geom.GetBounds(a, b, c).Size())

	a32 := a.AsVec2().Add(offset).ToVec2F32()
	b32 := b.AsVec2().Add(offset).ToVec2F32()
	c32 := c.AsVec2().Add(offset).ToVec2F32()

	path.MoveTo(a32.X, a32.Y)
	path.LineTo(b32.X, b32.Y)
	path.LineTo(c32.X, c32.Y)
	path.LineTo(a32.X, a32.Y)

	vs, is, op := d.preparePathToDraw(path, w, clr)
	d.drawPath(dst, vs, is, op)

	d.drawPivot(dst, pivot, clr)
}

func (d *Drawer) Pentagon(dst *ebiten.Image, pos geom.Point, size, w float64, rotation geom.Radian, clr color.Color) {
	path := d.GetPathForPentagon(pos, size, rotation)

	vs, is, op := d.preparePathToDraw(path, w, clr)
	d.drawPath(dst, vs, is, op)

	d.drawPivot(dst, pos, clr)
}

func (d *Drawer) GetPathForPentagon(pos geom.Point, size float64, rotation geom.Radian) vector.Path {
	size *= 1.4
	path := vector.Path{}
	offset := d.applyAnchor(d.Offset.AsVec2().Add(pos.AsVec2()), geom.Size{Width: size, Height: size})
	for i := 0; i <= 5; i++ {
		theta := 2*math.Pi*float64(i)/5 - math.Pi/2 + float64(rotation)
		x := offset.X + size*math.Cos(theta)
		y := offset.Y + size*math.Sin(theta)
		if i == 0 {
			path.MoveTo(float32(x), float32(y))
		} else {
			path.LineTo(float32(x), float32(y))
		}
	}

	return path
}

func (d *Drawer) Star(dst *ebiten.Image, pos geom.Point, size, w float64, rotation geom.Radian, clr color.Color) {
	path := d.GetPathForStar(pos, size, rotation)

	vs, is, op := d.preparePathToDraw(path, w, clr)
	d.drawPath(dst, vs, is, op)

	d.drawPivot(dst, pos, clr)
}

func (d *Drawer) GetPathForStar(pos geom.Point, size float64, rotation geom.Radian) vector.Path {
	size *= 1.4
	path := vector.Path{}
	offset := d.applyAnchor(d.Offset.AsVec2().Add(pos.AsVec2()), geom.Size{Width: size, Height: size})
	insize := size * 0.5
	for i := 0; i <= 5; i++ {
		theta := 2*math.Pi*float64(i)/5 - math.Pi/2 + float64(rotation)
		x := offset.X + size*math.Cos(theta)
		y := offset.Y + size*math.Sin(theta)
		if i == 0 {
			path.MoveTo(float32(x), float32(y))
		} else {
			path.LineTo(float32(x), float32(y))
		}
		x = offset.X + insize*math.Cos(theta+math.Pi/5)
		y = offset.Y + insize*math.Sin(theta+math.Pi/5)
		path.LineTo(float32(x), float32(y))
	}
	return path
}

func (d *Drawer) Cross(dst *ebiten.Image, pos geom.Point, size, w float64, rotation geom.Radian, clr color.Color) {
	path := d.GetPathForCross(pos, size, rotation)

	vs, is, op := d.preparePathToDraw(path, w, clr)
	d.drawPath(dst, vs, is, op)

	d.drawPivot(dst, pos, clr)
}

func (d *Drawer) GetPathForCross(pos geom.Point, size float64, rotation geom.Radian) vector.Path {
	size *= 1.4
	path := vector.Path{}
	offset := d.applyAnchor(d.Offset.AsVec2().Add(pos.AsVec2()), geom.Size{Width: size, Height: size})
	r := size
	cw := size / 2

	p1 := geom.NewVec2(offset.X-r, offset.Y+cw).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p2 := geom.NewVec2(offset.X-r, offset.Y-cw).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p3 := geom.NewVec2(offset.X-cw, offset.Y-cw).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p4 := geom.NewVec2(offset.X-cw, offset.Y-r).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p5 := geom.NewVec2(offset.X+cw, offset.Y-r).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p6 := geom.NewVec2(offset.X+cw, offset.Y-cw).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p7 := geom.NewVec2(offset.X+r, offset.Y-cw).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p8 := geom.NewVec2(offset.X+r, offset.Y+cw).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p9 := geom.NewVec2(offset.X+cw, offset.Y+cw).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p10 := geom.NewVec2(offset.X+cw, offset.Y+r).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p11 := geom.NewVec2(offset.X-cw, offset.Y+r).RotateAround(rotation, pos.AsVec2()).ToVec2F32()
	p12 := geom.NewVec2(offset.X-cw, offset.Y+cw).RotateAround(rotation, pos.AsVec2()).ToVec2F32()

	path.MoveTo(p1.X, p1.Y)
	path.LineTo(p2.X, p2.Y)
	path.LineTo(p3.X, p3.Y)
	path.LineTo(p4.X, p4.Y)
	path.LineTo(p5.X, p5.Y)
	path.LineTo(p6.X, p6.Y)
	path.LineTo(p7.X, p7.Y)
	path.LineTo(p8.X, p8.Y)
	path.LineTo(p9.X, p9.Y)
	path.LineTo(p10.X, p10.Y)
	path.LineTo(p11.X, p11.Y)
	path.LineTo(p12.X, p12.Y)
	path.LineTo(p1.X, p1.Y)

	return path
}
